package com.cencat.common.utils;

import lombok.experimental.UtilityClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 数据转换工具类
 * 提供各种数据类型之间的转换功能
 * 
 * @author cencat
 * @since 2024-01-01
 */
@UtilityClass

public class ConvertUtils {

    private static final Logger log = LoggerFactory.getLogger(ConvertUtils.class);

    /**
     * 默认日期格式
     */
    private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private static final String DEFAULT_DATE_ONLY_FORMAT = "yyyy-MM-dd";
    private static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
    
    /**
     * 常用日期格式
     */
    private static final String[] DATE_FORMATS = {
        "yyyy-MM-dd HH:mm:ss",
        "yyyy-MM-dd HH:mm",
        "yyyy-MM-dd",
        "yyyy/MM/dd HH:mm:ss",
        "yyyy/MM/dd HH:mm",
        "yyyy/MM/dd",
        "dd/MM/yyyy HH:mm:ss",
        "dd/MM/yyyy HH:mm",
        "dd/MM/yyyy",
        "dd-MM-yyyy HH:mm:ss",
        "dd-MM-yyyy HH:mm",
        "dd-MM-yyyy",
        "yyyyMMddHHmmss",
        "yyyyMMddHHmm",
        "yyyyMMdd"
    };

    // ==================== 字符串转换 ====================

    /**
     * 转换为字符串
     * 
     * @param obj 对象
     * @return 字符串
     */
    public static String toString(Object obj) {
        return toString(obj, null);
    }

    /**
     * 转换为字符串
     * 
     * @param obj 对象
     * @param defaultValue 默认值
     * @return 字符串
     */
    public static String toString(Object obj, String defaultValue) {
        if (obj == null) {
            return defaultValue;
        }
        
        if (obj instanceof String) {
            return (String) obj;
        }
        
        if (obj instanceof Date) {
            SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
            return sdf.format((Date) obj);
        }
        
        if (obj instanceof LocalDateTime) {
            return ((LocalDateTime) obj).format(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT));
        }
        
        if (obj instanceof LocalDate) {
            return ((LocalDate) obj).format(DateTimeFormatter.ofPattern(DEFAULT_DATE_ONLY_FORMAT));
        }
        
        return obj.toString();
    }

    // ==================== 数字转换 ====================

    /**
     * 转换为Integer
     * 
     * @param obj 对象
     * @return Integer
     */
    public static Integer toInteger(Object obj) {
        return toInteger(obj, null);
    }

    /**
     * 转换为Integer
     * 
     * @param obj 对象
     * @param defaultValue 默认值
     * @return Integer
     */
    public static Integer toInteger(Object obj, Integer defaultValue) {
        if (obj == null) {
            return defaultValue;
        }
        
        if (obj instanceof Integer) {
            return (Integer) obj;
        }
        
        if (obj instanceof Number) {
            return ((Number) obj).intValue();
        }
        
        if (obj instanceof String) {
            String str = ((String) obj).trim();
            if (str.isEmpty()) {
                return defaultValue;
            }
            
            try {
                // 处理小数点
                if (str.contains(".")) {
                    return Double.valueOf(str).intValue();
                }
                return Integer.valueOf(str);
            } catch (NumberFormatException e) {
                log.warn("转换Integer失败: {}", str);
                return defaultValue;
            }
        }
        
        if (obj instanceof Boolean) {
            return ((Boolean) obj) ? 1 : 0;
        }
        
        return defaultValue;
    }

    /**
     * 转换为Long
     * 
     * @param obj 对象
     * @return Long
     */
    public static Long toLong(Object obj) {
        return toLong(obj, null);
    }

    /**
     * 转换为Long
     * 
     * @param obj 对象
     * @param defaultValue 默认值
     * @return Long
     */
    public static Long toLong(Object obj, Long defaultValue) {
        if (obj == null) {
            return defaultValue;
        }
        
        if (obj instanceof Long) {
            return (Long) obj;
        }
        
        if (obj instanceof Number) {
            return ((Number) obj).longValue();
        }
        
        if (obj instanceof String) {
            String str = ((String) obj).trim();
            if (str.isEmpty()) {
                return defaultValue;
            }
            
            try {
                // 处理小数点
                if (str.contains(".")) {
                    return Double.valueOf(str).longValue();
                }
                return Long.valueOf(str);
            } catch (NumberFormatException e) {
                log.warn("转换Long失败: {}", str);
                return defaultValue;
            }
        }
        
        if (obj instanceof Boolean) {
            return ((Boolean) obj) ? 1L : 0L;
        }
        
        if (obj instanceof Date) {
            return ((Date) obj).getTime();
        }
        
        return defaultValue;
    }

    /**
     * 转换为Double
     * 
     * @param obj 对象
     * @return Double
     */
    public static Double toDouble(Object obj) {
        return toDouble(obj, null);
    }

    /**
     * 转换为Double
     * 
     * @param obj 对象
     * @param defaultValue 默认值
     * @return Double
     */
    public static Double toDouble(Object obj, Double defaultValue) {
        if (obj == null) {
            return defaultValue;
        }
        
        if (obj instanceof Double) {
            return (Double) obj;
        }
        
        if (obj instanceof Number) {
            return ((Number) obj).doubleValue();
        }
        
        if (obj instanceof String) {
            String str = ((String) obj).trim();
            if (str.isEmpty()) {
                return defaultValue;
            }
            
            try {
                return Double.valueOf(str);
            } catch (NumberFormatException e) {
                log.warn("转换Double失败: {}", str);
                return defaultValue;
            }
        }
        
        if (obj instanceof Boolean) {
            return ((Boolean) obj) ? 1.0 : 0.0;
        }
        
        return defaultValue;
    }

    /**
     * 转换为Float
     * 
     * @param obj 对象
     * @return Float
     */
    public static Float toFloat(Object obj) {
        return toFloat(obj, null);
    }

    /**
     * 转换为Float
     * 
     * @param obj 对象
     * @param defaultValue 默认值
     * @return Float
     */
    public static Float toFloat(Object obj, Float defaultValue) {
        if (obj == null) {
            return defaultValue;
        }
        
        if (obj instanceof Float) {
            return (Float) obj;
        }
        
        if (obj instanceof Number) {
            return ((Number) obj).floatValue();
        }
        
        if (obj instanceof String) {
            String str = ((String) obj).trim();
            if (str.isEmpty()) {
                return defaultValue;
            }
            
            try {
                return Float.valueOf(str);
            } catch (NumberFormatException e) {
                log.warn("转换Float失败: {}", str);
                return defaultValue;
            }
        }
        
        if (obj instanceof Boolean) {
            return ((Boolean) obj) ? 1.0f : 0.0f;
        }
        
        return defaultValue;
    }

    /**
     * 转换为BigDecimal
     * 
     * @param obj 对象
     * @return BigDecimal
     */
    public static BigDecimal toBigDecimal(Object obj) {
        return toBigDecimal(obj, null);
    }

    /**
     * 转换为BigDecimal
     * 
     * @param obj 对象
     * @param defaultValue 默认值
     * @return BigDecimal
     */
    public static BigDecimal toBigDecimal(Object obj, BigDecimal defaultValue) {
        if (obj == null) {
            return defaultValue;
        }
        
        if (obj instanceof BigDecimal) {
            return (BigDecimal) obj;
        }
        
        if (obj instanceof Number) {
            return new BigDecimal(obj.toString());
        }
        
        if (obj instanceof String) {
            String str = ((String) obj).trim();
            if (str.isEmpty()) {
                return defaultValue;
            }
            
            try {
                return new BigDecimal(str);
            } catch (NumberFormatException e) {
                log.warn("转换BigDecimal失败: {}", str);
                return defaultValue;
            }
        }
        
        if (obj instanceof Boolean) {
            return ((Boolean) obj) ? BigDecimal.ONE : BigDecimal.ZERO;
        }
        
        return defaultValue;
    }

    /**
     * 转换为BigInteger
     * 
     * @param obj 对象
     * @return BigInteger
     */
    public static BigInteger toBigInteger(Object obj) {
        return toBigInteger(obj, null);
    }

    /**
     * 转换为BigInteger
     * 
     * @param obj 对象
     * @param defaultValue 默认值
     * @return BigInteger
     */
    public static BigInteger toBigInteger(Object obj, BigInteger defaultValue) {
        if (obj == null) {
            return defaultValue;
        }
        
        if (obj instanceof BigInteger) {
            return (BigInteger) obj;
        }
        
        if (obj instanceof Number) {
            return BigInteger.valueOf(((Number) obj).longValue());
        }
        
        if (obj instanceof String) {
            String str = ((String) obj).trim();
            if (str.isEmpty()) {
                return defaultValue;
            }
            
            try {
                // 处理小数点
                if (str.contains(".")) {
                    return new BigInteger(str.split("\\.")[0]);
                }
                return new BigInteger(str);
            } catch (NumberFormatException e) {
                log.warn("转换BigInteger失败: {}", str);
                return defaultValue;
            }
        }
        
        if (obj instanceof Boolean) {
            return ((Boolean) obj) ? BigInteger.ONE : BigInteger.ZERO;
        }
        
        return defaultValue;
    }

    // ==================== 布尔值转换 ====================

    /**
     * 转换为Boolean
     * 
     * @param obj 对象
     * @return Boolean
     */
    public static Boolean toBoolean(Object obj) {
        return toBoolean(obj, null);
    }

    /**
     * 转换为Boolean
     * 
     * @param obj 对象
     * @param defaultValue 默认值
     * @return Boolean
     */
    public static Boolean toBoolean(Object obj, Boolean defaultValue) {
        if (obj == null) {
            return defaultValue;
        }
        
        if (obj instanceof Boolean) {
            return (Boolean) obj;
        }
        
        if (obj instanceof Number) {
            return ((Number) obj).intValue() != 0;
        }
        
        if (obj instanceof String) {
            String str = ((String) obj).trim().toLowerCase();
            if (str.isEmpty()) {
                return defaultValue;
            }
            
            // 真值
            if ("true".equals(str) || "yes".equals(str) || "y".equals(str) || 
                "1".equals(str) || "on".equals(str) || "enabled".equals(str)) {
                return true;
            }
            
            // 假值
            if ("false".equals(str) || "no".equals(str) || "n".equals(str) || 
                "0".equals(str) || "off".equals(str) || "disabled".equals(str)) {
                return false;
            }
            
            return defaultValue;
        }
        
        return defaultValue;
    }

    // ==================== 日期转换 ====================

    /**
     * 转换为Date
     * 
     * @param obj 对象
     * @return Date
     */
    public static Date toDate(Object obj) {
        return toDate(obj, null);
    }

    /**
     * 转换为Date
     * 
     * @param obj 对象
     * @param defaultValue 默认值
     * @return Date
     */
    public static Date toDate(Object obj, Date defaultValue) {
        if (obj == null) {
            return defaultValue;
        }
        
        if (obj instanceof Date) {
            return (Date) obj;
        }
        
        if (obj instanceof Long) {
            return new Date((Long) obj);
        }
        
        if (obj instanceof Number) {
            return new Date(((Number) obj).longValue());
        }
        
        if (obj instanceof String) {
            String str = ((String) obj).trim();
            if (str.isEmpty()) {
                return defaultValue;
            }
            
            // 尝试解析时间戳
            if (str.matches("\\d+")) {
                try {
                    long timestamp = Long.parseLong(str);
                    // 判断是秒还是毫秒
                    if (timestamp < 10000000000L) {
                        timestamp *= 1000;
                    }
                    return new Date(timestamp);
                } catch (NumberFormatException e) {
                    // 忽略
                }
            }
            
            // 尝试各种日期格式
            for (String format : DATE_FORMATS) {
                try {
                    SimpleDateFormat sdf = new SimpleDateFormat(format);
                    return sdf.parse(str);
                } catch (ParseException e) {
                    // 继续尝试下一个格式
                }
            }
            
            log.warn("转换Date失败: {}", str);
            return defaultValue;
        }
        
        if (obj instanceof LocalDateTime) {
            return java.sql.Timestamp.valueOf((LocalDateTime) obj);
        }
        
        if (obj instanceof LocalDate) {
            return java.sql.Date.valueOf((LocalDate) obj);
        }
        
        return defaultValue;
    }

    /**
     * 转换为LocalDateTime
     * 
     * @param obj 对象
     * @return LocalDateTime
     */
    public static LocalDateTime toLocalDateTime(Object obj) {
        return toLocalDateTime(obj, null);
    }

    /**
     * 转换为LocalDateTime
     * 
     * @param obj 对象
     * @param defaultValue 默认值
     * @return LocalDateTime
     */
    public static LocalDateTime toLocalDateTime(Object obj, LocalDateTime defaultValue) {
        if (obj == null) {
            return defaultValue;
        }
        
        if (obj instanceof LocalDateTime) {
            return (LocalDateTime) obj;
        }
        
        if (obj instanceof Date) {
            return ((Date) obj).toInstant()
                    .atZone(java.time.ZoneId.systemDefault())
                    .toLocalDateTime();
        }
        
        if (obj instanceof Long) {
            return java.time.Instant.ofEpochMilli((Long) obj)
                    .atZone(java.time.ZoneId.systemDefault())
                    .toLocalDateTime();
        }
        
        if (obj instanceof Number) {
            return java.time.Instant.ofEpochMilli(((Number) obj).longValue())
                    .atZone(java.time.ZoneId.systemDefault())
                    .toLocalDateTime();
        }
        
        if (obj instanceof String) {
            String str = ((String) obj).trim();
            if (str.isEmpty()) {
                return defaultValue;
            }
            
            // 尝试解析时间戳
            if (str.matches("\\d+")) {
                try {
                    long timestamp = Long.parseLong(str);
                    // 判断是秒还是毫秒
                    if (timestamp < 10000000000L) {
                        timestamp *= 1000;
                    }
                    return java.time.Instant.ofEpochMilli(timestamp)
                            .atZone(java.time.ZoneId.systemDefault())
                            .toLocalDateTime();
                } catch (NumberFormatException e) {
                    // 忽略
                }
            }
            
            // 尝试各种日期格式
            for (String format : DATE_FORMATS) {
                try {
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
                    return LocalDateTime.parse(str, formatter);
                } catch (DateTimeParseException e) {
                    // 继续尝试下一个格式
                }
            }
            
            log.warn("转换LocalDateTime失败: {}", str);
            return defaultValue;
        }
        
        if (obj instanceof LocalDate) {
            return ((LocalDate) obj).atStartOfDay();
        }
        
        return defaultValue;
    }

    /**
     * 转换为LocalDate
     * 
     * @param obj 对象
     * @return LocalDate
     */
    public static LocalDate toLocalDate(Object obj) {
        return toLocalDate(obj, null);
    }

    /**
     * 转换为LocalDate
     * 
     * @param obj 对象
     * @param defaultValue 默认值
     * @return LocalDate
     */
    public static LocalDate toLocalDate(Object obj, LocalDate defaultValue) {
        if (obj == null) {
            return defaultValue;
        }
        
        if (obj instanceof LocalDate) {
            return (LocalDate) obj;
        }
        
        if (obj instanceof LocalDateTime) {
            return ((LocalDateTime) obj).toLocalDate();
        }
        
        if (obj instanceof Date) {
            return ((Date) obj).toInstant()
                    .atZone(java.time.ZoneId.systemDefault())
                    .toLocalDate();
        }
        
        if (obj instanceof Long) {
            return java.time.Instant.ofEpochMilli((Long) obj)
                    .atZone(java.time.ZoneId.systemDefault())
                    .toLocalDate();
        }
        
        if (obj instanceof Number) {
            return java.time.Instant.ofEpochMilli(((Number) obj).longValue())
                    .atZone(java.time.ZoneId.systemDefault())
                    .toLocalDate();
        }
        
        if (obj instanceof String) {
            String str = ((String) obj).trim();
            if (str.isEmpty()) {
                return defaultValue;
            }
            
            // 尝试解析时间戳
            if (str.matches("\\d+")) {
                try {
                    long timestamp = Long.parseLong(str);
                    // 判断是秒还是毫秒
                    if (timestamp < 10000000000L) {
                        timestamp *= 1000;
                    }
                    return java.time.Instant.ofEpochMilli(timestamp)
                            .atZone(java.time.ZoneId.systemDefault())
                            .toLocalDate();
                } catch (NumberFormatException e) {
                    // 忽略
                }
            }
            
            // 尝试各种日期格式
            for (String format : DATE_FORMATS) {
                try {
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
                    if (format.contains("HH")) {
                        return LocalDateTime.parse(str, formatter).toLocalDate();
                    } else {
                        return LocalDate.parse(str, formatter);
                    }
                } catch (DateTimeParseException e) {
                    // 继续尝试下一个格式
                }
            }
            
            log.warn("转换LocalDate失败: {}", str);
            return defaultValue;
        }
        
        return defaultValue;
    }

    // ==================== 集合转换 ====================

    /**
     * 转换为List
     * 
     * @param obj 对象
     * @param <T> 泛型类型
     * @return List
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> toList(Object obj) {
        if (obj == null) {
            return new ArrayList<>();
        }
        
        if (obj instanceof List) {
            return (List<T>) obj;
        }
        
        if (obj instanceof Collection) {
            return new ArrayList<>((Collection<T>) obj);
        }
        
        if (obj.getClass().isArray()) {
            Object[] array = (Object[]) obj;
            return Arrays.stream(array)
                    .map(item -> (T) item)
                    .collect(Collectors.toList());
        }
        
        if (obj instanceof String) {
            String str = (String) obj;
            if (str.trim().isEmpty()) {
                return new ArrayList<>();
            }
            
            // 尝试按逗号分割
            String[] parts = str.split(",");
            return Arrays.stream(parts)
                    .map(String::trim)
                    .map(item -> (T) item)
                    .collect(Collectors.toList());
        }
        
        // 单个元素转为List
        List<T> list = new ArrayList<>();
        list.add((T) obj);
        return list;
    }

    /**
     * 转换为Set
     * 
     * @param obj 对象
     * @param <T> 泛型类型
     * @return Set
     */
    @SuppressWarnings("unchecked")
    public static <T> Set<T> toSet(Object obj) {
        if (obj == null) {
            return new HashSet<>();
        }
        
        if (obj instanceof Set) {
            return (Set<T>) obj;
        }
        
        if (obj instanceof Collection) {
            return new HashSet<>((Collection<T>) obj);
        }
        
        List<T> list = toList(obj);
        return new HashSet<>(list);
    }

    /**
     * 转换为数组
     * 
     * @param obj 对象
     * @param componentType 数组元素类型
     * @param <T> 泛型类型
     * @return 数组
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] toArray(Object obj, Class<T> componentType) {
        if (obj == null) {
            return (T[]) java.lang.reflect.Array.newInstance(componentType, 0);
        }
        
        if (obj.getClass().isArray()) {
            return (T[]) obj;
        }
        
        List<T> list = toList(obj);
        T[] array = (T[]) java.lang.reflect.Array.newInstance(componentType, list.size());
        return list.toArray(array);
    }

    // ==================== 通用转换 ====================

    /**
     * 通用类型转换
     * 
     * @param obj 对象
     * @param targetType 目标类型
     * @param <T> 泛型类型
     * @return 转换后的对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T convert(Object obj, Class<T> targetType) {
        if (obj == null) {
            return null;
        }
        
        if (targetType.isAssignableFrom(obj.getClass())) {
            return (T) obj;
        }
        
        // 字符串类型
        if (targetType == String.class) {
            return (T) toString(obj);
        }
        
        // 数字类型
        if (targetType == Integer.class || targetType == int.class) {
            return (T) toInteger(obj);
        }
        if (targetType == Long.class || targetType == long.class) {
            return (T) toLong(obj);
        }
        if (targetType == Double.class || targetType == double.class) {
            return (T) toDouble(obj);
        }
        if (targetType == Float.class || targetType == float.class) {
            return (T) toFloat(obj);
        }
        if (targetType == BigDecimal.class) {
            return (T) toBigDecimal(obj);
        }
        if (targetType == BigInteger.class) {
            return (T) toBigInteger(obj);
        }
        
        // 布尔类型
        if (targetType == Boolean.class || targetType == boolean.class) {
            return (T) toBoolean(obj);
        }
        
        // 日期类型
        if (targetType == Date.class) {
            return (T) toDate(obj);
        }
        if (targetType == LocalDateTime.class) {
            return (T) toLocalDateTime(obj);
        }
        if (targetType == LocalDate.class) {
            return (T) toLocalDate(obj);
        }
        
        // 集合类型
        if (targetType == List.class) {
            return (T) toList(obj);
        }
        if (targetType == Set.class) {
            return (T) toSet(obj);
        }
        
        // 枚举类型
        if (targetType.isEnum()) {
            return convertToEnum(obj, (Class<Enum>) targetType);
        }
        
        log.warn("不支持的类型转换: {} -> {}", obj.getClass().getSimpleName(), targetType.getSimpleName());
        return null;
    }

    /**
     * 转换为枚举
     * 
     * @param obj 对象
     * @param enumClass 枚举类
     * @param <T> 枚举类型
     * @return 枚举值
     */
    @SuppressWarnings("unchecked")
    private static <T> T convertToEnum(Object obj, Class<Enum> enumClass) {
        if (obj == null) {
            return null;
        }
        
        if (enumClass.isAssignableFrom(obj.getClass())) {
            return (T) obj;
        }
        
        String str = toString(obj);
        if (CencatStringUtils.isBlank(str)) {
            return null;
        }
        
        try {
            return (T) Enum.valueOf(enumClass, str.toUpperCase());
        } catch (IllegalArgumentException e) {
            // 尝试按名称匹配
            Enum[] enumConstants = enumClass.getEnumConstants();
            for (Enum enumConstant : enumConstants) {
                if (enumConstant.name().equalsIgnoreCase(str)) {
                    return (T) enumConstant;
                }
            }
            
            log.warn("转换枚举失败: {} -> {}", str, enumClass.getSimpleName());
            return null;
        }
    }

    /**
     * 安全转换（不抛出异常）
     * 
     * @param obj 对象
     * @param targetType 目标类型
     * @param defaultValue 默认值
     * @param <T> 泛型类型
     * @return 转换后的对象
     */
    public static <T> T safeConvert(Object obj, Class<T> targetType, T defaultValue) {
        try {
            T result = convert(obj, targetType);
            return result != null ? result : defaultValue;
        } catch (Exception e) {
            log.warn("类型转换异常: {}", e.getMessage());
            return defaultValue;
        }
    }

    /**
     * 批量转换
     * 
     * @param objList 对象列表
     * @param targetType 目标类型
     * @param <T> 泛型类型
     * @return 转换后的列表
     */
    public static <T> List<T> convertList(List<?> objList, Class<T> targetType) {
        if (objList == null || objList.isEmpty()) {
            return new ArrayList<>();
        }
        
        return objList.stream()
                .map(obj -> convert(obj, targetType))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 检查是否可以转换
     * 
     * @param obj 对象
     * @param targetType 目标类型
     * @return 是否可以转换
     */
    public static boolean canConvert(Object obj, Class<?> targetType) {
        if (obj == null || targetType == null) {
            return false;
        }
        
        try {
            Object result = convert(obj, targetType);
            return result != null;
        } catch (Exception e) {
            return false;
        }
    }
}